﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using System.Windows.Forms;
using AccessControl.Business;
using AccessControl.Common.Enumerations;
using AccessControl.SecurityMonitoring.Properties;
using AccessControl.SecurityMonitoring.Struct;
using AccessControl.Utility.EnumHelper;
using AccessControl.Utility.Tools;
using DevExpress.XtraEditors;


namespace AccessControl.SecurityMonitoring.Form
{
    [CallbackBehavior(
    ConcurrencyMode = ConcurrencyMode.Single,
    UseSynchronizationContext = false)]
    public partial class Monitoring : XtraForm, WorkflowEngineServerCallback
    {

        #region Fields

        public static bool showRetryMessage = true;
        private bool isRetryMessagevisible = false;
        private SynchronizationContext _uiSyncContext = null;
        private WorkflowEngineServerClient _workflowEngineServerClient;
        private Guid _applicationID = Guid.NewGuid();

        private readonly NotifyForm _notifyForm = new NotifyForm();

        private readonly Dictionary<Int64, PersonInfo> _eventlogList = new Dictionary<long, PersonInfo>();

        
        #endregion

        #region Constructor

        public Monitoring()
        {
            InitializeComponent();
        }

        #endregion

        #region Event Handler

        private void MainForm_Load(object sender, EventArgs e)
        {
            //_notifyForm.Show();
            //_notifyForm.Hide();


            OpenServiceConnection();

            _notifyForm.MonitoringForm = this;

            SetNotifyFormState();

            LoadWorkflowGridData();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            CloseServiceConnection();
        }

        private void gridView_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
        {
            if (e.Column == gridColumnDateRegistered)
            {
                var pc = new PersianCalendar();
                var date = (DateTime)e.Value;
                e.DisplayText = String.Format("{0}/{1}/{2} - {3}:{4}:{5}", pc.GetYear(date), pc.GetMonth(date), pc.GetDayOfMonth(date), date.Hour, date.Minute, date.Second);
            }
        }

        private void gridViewEventLog_FocusedRowChanged(object sender, DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs e)
        {
            DisplayPersonDetailedInfo();
        }

        private void simpleButtonSettings_Click(object sender, EventArgs e)
        {
            var workflowSelector = new WorkflowSelector();
            var result = workflowSelector.ShowDialog();
            if (result == DialogResult.OK)
            {
                Settings.Default.WorkflowList = workflowSelector.SelectedWorkflowList;
                Settings.Default.Save();
                CloseServiceConnection();
                LoadWorkflowGridData();
                OpenServiceConnection();
            }
        }

        private void checkButtonShowNotifyForm_CheckedChanged(object sender, EventArgs e)
        {
            SetNotifyFormState();
        }

        private void gridViewWorkflow_RowCellClick(object sender, DevExpress.XtraGrid.Views.Grid.RowCellClickEventArgs e)
        {
            if (!gridViewWorkflow.IsDataRow(e.RowHandle))
                return;
            if (e.Column == gridColumnButton)
            {
                var workflowID =
                    Int32.Parse(
                        gridViewWorkflow.GetDataRow(gridViewWorkflow.GetSelectedRows()[0])["pkWorkflow"].
                            ToString());
                _workflowEngineServerClient.LetOnePersonPass(workflowID);
            }

        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (isRetryMessagevisible) return;

            ThreadPool.QueueUserWorkItem(CheckServerConnection);
        }

        private void CheckServerConnection(object sender)
        {
            try
            {
                _workflowEngineServerClient.CheckConnection();
            }
            catch (Exception)
            {
                CloseServiceConnection();
                _applicationID = Guid.NewGuid();
                OpenServiceConnection();

            }
        }

        private void simpleButtonServiceSettings_Click(object sender, EventArgs e)
        {
            WindowsServiceManager.GetInstance().ShowDialog();
        }

        #endregion

        #region Private Method

        private void CloseServiceConnection()
        {
            try
            {
                _workflowEngineServerClient.UnRegister(_applicationID.ToString());
                _workflowEngineServerClient.Close();
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message, "CloseServiceConnection", eventLevelConstants.Error);
            }
        }

        private void OpenServiceConnection()
        {
            try
            {
                _uiSyncContext = SynchronizationContext.Current;
                _workflowEngineServerClient = new WorkflowEngineServerClient(new InstanceContext(this), "TcpBinding");
                _workflowEngineServerClient.ClientCredentials.Windows.ClientCredential.Domain = Settings.Default.Domain;
                _workflowEngineServerClient.ClientCredentials.Windows.ClientCredential.UserName = Settings.Default.Username;
                _workflowEngineServerClient.ClientCredentials.Windows.ClientCredential.Password = Settings.Default.Password;
                _workflowEngineServerClient.Open();
                var workflowList = (from string workflow in Settings.Default.WorkflowList
                                    select Byte.Parse(workflow)).Select(dummy => (int)dummy).ToList();
                _workflowEngineServerClient.Register(_applicationID.ToString(), workflowList.ToArray());
                showRetryMessage = true;
            }
            catch (Exception ex)
            {
                if ((showRetryMessage) && (!isRetryMessagevisible))
                {
                    isRetryMessagevisible = true;
                    Invoke(new EventHandler(ShowMessageBoxResult));


                }
                WriteLog(ex.Message, "OpenServiceConnection", eventLevelConstants.Error);
            }
        }

        private void ShowMessageBoxResult(object sender, EventArgs eventArgs)
        {
            var result = XtraMessageBox.Show(this, "امکان برقراری ارتباط با سرور نمی باشد", "سیستم کنترل تردد آریابان", MessageBoxButtons.RetryCancel, MessageBoxIcon.Stop);
            if (result == DialogResult.Cancel)
                showRetryMessage = false;
            isRetryMessagevisible = false;
        }

        private void RefreshGrid(object sender, EventArgs e)
        {

            var table = new DataTable();
            var pkEventLogColumn = new DataColumn("pkEventLog", typeof(Int64));
            var fkPersonColumn = new DataColumn("fkPerson", typeof(String));
            var fullNameColumn = new DataColumn("FullName", typeof(String));
            var eventTypeColumn = new DataColumn("EventType", typeof(String));
            var reasonColumn = new DataColumn("Reason", typeof(String));
            var resultColumn = new DataColumn("Result", typeof(String));
            var dateRegisteredColumn = new DataColumn("DateRegistered", typeof(DateTime));
            table.Columns.AddRange(new[] { pkEventLogColumn, fkPersonColumn, fullNameColumn, eventTypeColumn, resultColumn, reasonColumn, dateRegisteredColumn });
            foreach (var personInfo in _eventlogList.Values)
            {
                var row = table.NewRow();
                row[pkEventLogColumn] = personInfo.PkEventLog;
                row[fkPersonColumn] = personInfo.FkPerson;
                row[fullNameColumn] = personInfo.FullName;
                row[eventTypeColumn] = personInfo.EventType;
                row[reasonColumn] = personInfo.Reason;
                row[resultColumn] = personInfo.Result.GetDescription();
                row[dateRegisteredColumn] = personInfo.DateRegistered;
                table.Rows.Add(row);
            }

            gridControlEventLog.DataSource = table;
            DisplayPersonDetailedInfo();

        }

        private void DisplayPersonDetailedInfo()
        {
            var pkPerson = gridViewEventLog.GetDataRow(gridViewEventLog.GetSelectedRows()[0])["fkPerson"].ToString();
            var personRow = PersonBusiness.SelectByFilter(String.Format("pkPerson='{0}'", pkPerson)).Single();
            textEditFullName.Text = String.Format("{0} {1}", personRow.PersonFirstName, personRow.PersonLastName);
            textEditPersonTitle.Text = ((PersonTitleConstants)personRow.PersonTitle).GetDescription();
            textEditPersonIsMale.Text = personRow.PersonIsMale ? "مذکر" : "مونث";
            textEditPersonRefNumber.Text = personRow.PersonRefNumber;
            var pc = new PersianCalendar();
            if (!personRow.IsPersonExpireDateNull())
                textEditPersonExpireDate.Text = String.Format("{0}/{1}/{2}",
                    pc.GetYear(personRow.PersonExpireDate), pc.GetMonth(personRow.PersonExpireDate), pc.GetDayOfMonth(personRow.PersonExpireDate));
            memoEditPersonDesc.Text = personRow.PersonDesc;
        }

        private void LoadWorkflowGridData()
        {
            try
            {
                var dt = new DataTable();
                var colPkWokflow = new DataColumn("pkWorkflow", typeof(Int32));
                var colWorkflowName = new DataColumn("WorkflowName", typeof(String));
                dt.Columns.Add(colPkWokflow);
                dt.Columns.Add(colWorkflowName);
                foreach (var workflowID in Settings.Default.WorkflowList)
                {
                    var row = dt.NewRow();
                    row[colPkWokflow] = Int32.Parse(workflowID);
                    var a = WorkflowBusiness.SelectByFilter(String.Format("pkWorkflow={0}", workflowID));
                    if (a == null)
                        continue;
                    row[colWorkflowName] =
                        WorkflowBusiness.SelectByFilter(String.Format("pkWorkflow={0}", workflowID)).Single().
                            WorkflowName;
                    dt.Rows.Add(row);
                }
                gridControlWorkflow.DataSource = dt;
            }
            catch (Exception ex)
            { WriteLog(ex.Message, "LoadWorkflowGridData", eventLevelConstants.Error); }
        }

        private void SetNotifyFormState()
        {
            if (checkButtonShowNotifyForm.Checked)
            {
                _notifyForm.Show();
                checkButtonShowNotifyForm.Text =
                    @"عدم نمایش تصویر مراجعین";
            }

            else
            {
                _notifyForm.Hide();
                checkButtonShowNotifyForm.Text =
                    @"نمایش تصویر مراجعین";
            }
        }

        private static void WriteLog(String message, String callerMethod, eventLevelConstants level)
        {
            LogFile.WriteLog(LogFile.DefaultLogfileLocation + "Security Monitoring\\" + DateTime.Now.Date.ToString("yyyyMMdd") + " " + "MainForm " + callerMethod + ".txt", level, message);
        }

        #endregion

        #region Implementation of WorkflowEngineServerCallback

        public NotifiyClientWorkflowEventOccuredResponse NotifiyClientWorkflowEventOccured(NotifiyClientWorkflowEventOccuredSolicit request)
        {
            try
            {
                var eventLogRow =
                    (AccessControlDS.tblEventLogRow)request.eventLogDataTable.Select().Single();
                var personRow =
                    PersonBusiness.SelectByFilter(String.Format("pkPerson = '{0}'", eventLogRow.fkPerson)).
                        SingleOrDefault();
                

                var personInfo = new PersonInfo();

                personInfo.PkEventLog = eventLogRow.pkEventLog;
                if ((EventResultConstants)eventLogRow.Result != EventResultConstants.Success)
                    personInfo.Reason = eventLogRow.Reason;
                else
                    if ((Settings.Default.NotifyGroupType!=null) && ((int)Settings.Default.NotifyGroupType != 0))
                        personInfo.Reason = PersonGroupBusiness.GetGroupName(eventLogRow.fkPerson,
                                                                             (int)Settings.Default.NotifyGroupType);
                personInfo.Result = ((EventResultConstants)eventLogRow.Result);
                personInfo.FullName = String.Format("{0} {1}", personRow.PersonFirstName,
                                                    personRow.PersonLastName);
                personInfo.Pic = personRow.PersonPhoto;
                personInfo.DateRegistered = eventLogRow.DateRegistered;
                personInfo.FkPerson = eventLogRow.fkPerson;
                personInfo.EventType = eventLogRow.EventType;
                personInfo.HasTwineEvent = EventLogBusiness.HasTwinEvent(personInfo.PkEventLog);

                if (_eventlogList.ContainsKey(personInfo.PkEventLog))
                    _eventlogList.Remove(personInfo.PkEventLog);
                _eventlogList.Add(personInfo.PkEventLog, personInfo);
                Invoke(new EventHandler(RefreshGrid));
                _notifyForm.DiplayPersonInfo(personInfo);
            }
            catch (Exception ex)
            {
                WriteLog(ex.Message, "NotifiyClientWorkflowEventOccured", eventLevelConstants.Error);
            }
            return new NotifiyClientWorkflowEventOccuredResponse();
        }

        public bool CheckConnectionAlive()
        {
            return true;
        }

        #endregion

    }
}
